import { createNamespacedHelpers } from 'vuex'
import { Ref, computed } from 'vue'
import store from './index'

/**
 * 实际遍历函数
 * @param moduleName 模块名
 * @param mapStoreFcn 被调用的辅助函数
 * @param type true => Mutations, Actions; false => States, Getters
 * @param mapper 遍历属性名
 * @returns
 */
function mapStore(_moduleName: string, mapStoreFcn: Function, type: boolean, props: string[] | string) {
  const storeState = {} as any
  const propsList = mapStoreFcn(props)
  Object.keys(propsList).forEach(item => {
    const fn = propsList[item].bind({ $store: store })
    // Mutations, Actions 为方法，返回函数体， States, Getters 为计算属性，返回非响应式数据
    storeState[item] = type ? fn : computed(fn)
  })
  return storeState
}

/**
 * state辅助函数
 * @param moduleName 模块名
 * @param mapper 属性数组 或者 单属性
 * @returns
 */
export function useState<T>(moduleName: string, props: string[] | string): T {
  // 创建专属命名空间的store
  const store = createNamespacedHelpers(moduleName).mapState
  return mapStore(moduleName, store, false, props)
}

/**
 * getters辅助函数
 * @param moduleName 模块名
 * @param mapper 属性数组 或者 单属性
 * @returns
 */
export function useGetters<T>(moduleName: string, props: string[] | string): T {
  // 创建专属命名空间的store
  const store = createNamespacedHelpers(moduleName).mapGetters
  return mapStore(moduleName, store, false, props)
}

/**
 * actions辅助函数
 * @param moduleName 模块名
 * @param mapper 属性数组 或者 单属性
 * @returns
 */
export function useActions<T>(moduleName: string, props: string[] | string): T {
  // 创建专属命名空间的store
  const stores = createNamespacedHelpers(moduleName).mapActions
  return mapStore(moduleName, stores, true, props)
}

/**
 * mutations辅助函数
 * @param moduleName 模块名
 * @param mapper 属性数组 或者 单属性
 * @returns
 */
export function useMutations<T>(moduleName: string, props: string[] | string): T {
  // 创建专属命名空间的store
  const stores = createNamespacedHelpers(moduleName).mapMutations
  return mapStore(moduleName, stores, true, props)
}

// state参数类型推导
type stateFun<T> = T
export type ModuleState<T> = {
  [key in keyof T]: Ref<stateFun<T[key]>>
}

// getter参数类型推导
type getterFun<T> = T extends (state: any) => any ? ReturnType<T> : never
export type ModuleGetters<T> = {
  [key in keyof T]: Ref<getterFun<T[key]>>
}

// action参数类型推导
type actionFun<T> = T extends (context: any, ...args: infer U) => any ? (...args: U) => ReturnType<T> : never
export type ModuleActions<T> = {
  [key in keyof T]: actionFun<T[key]>
}

// mutation参数类型推导
type mutationFun<T> = T extends (first: any, ...args: infer U) => any ? (...args: U) => ReturnType<T> : never
export type ModuleMutations<T> = {
  [key in keyof T]: mutationFun<T[key]>
}
